package com.idudiao.sc.common.log.aspect;

import cn.hutool.core.util.ArrayUtil;
import cn.hutool.core.util.ClassUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.ReflectUtil;
import cn.hutool.json.JSONArray;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.idudiao.sc.common.log.annotation.OperationLog;
import com.idudiao.sc.common.log.event.OperationLogEvent;
import com.idudiao.sc.common.log.util.LogUtils;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;

import java.lang.reflect.Field;
import java.util.Optional;

/**
 * @author songyinyin
 * @date 2019/1/8 18:07
 */
@Slf4j
//@Aspect
public class OperationLogAspect {

    private final static String KEY = "operation_type";

    /*@Around("(@annotation(operationLog) && @annotation(apiOperation))")
    public Object around(ProceedingJoinPoint point, OperationLog operationLog, ApiOperation apiOperation) throws Throwable {
        String strClassName = point.getTarget().getClass().getName();
        String strMethodName = point.getSignature().getName();
        log.debug("[类名]:{},[方法]:{}", strClassName, strMethodName);

        OperationLogDTO dto = LogUtils.getOperationLog();
        // 默认操作
        dto.setOperation(apiOperation.value());
        // 业务模块 com.dhcc.aml.modules.flow.controller.SysUserController --> flow
        dto.setModule(strClassName.split("\\.")[4]);

        // 装载key和notes
        if (operationLog.value()) {
            setKeyAndNotes(point, operationLog, dto);
        }

        // 发送异步日志事件
        Long startTime = System.currentTimeMillis();
        Object obj = null;
        try {
            obj = point.proceed();
        } catch (Exception e) {
            BaseResponse response = new BaseResponse(WebUtils.getResponse().getStatus(), e.getMessage());
            Long endTime = System.currentTimeMillis();
            // 从redis里获取操作的对应关系
            setOperationFromRedis(dto, obj);
            dto.setTime(endTime - startTime);
            dto.setResult(JSONUtil.toJsonStr(response));
            SpringContextHolder.publishEvent(new OperationLogEvent(dto));
            throw e;
        }
        Long endTime = System.currentTimeMillis();
        // 从redis里获取操作的对应关系
        setOperationFromRedis(dto, obj);
        dto.setTime(endTime - startTime);
        dto.setResult(JSONUtil.toJsonStr(obj));
        SpringContextHolder.publishEvent(new OperationLogEvent(dto));
        return obj;
    }

    *//**
     * 从redis里获取操作的对应关系
     *
     * @param dto 操作日志实体
     * @param obj 方法返回结果
     *//*
    private void setOperationFromRedis(OperationLogDTO dto, Object obj) {
        if (obj instanceof ObjectRestResponse) {
            ObjectRestResponse response = (ObjectRestResponse) obj;
            if (ObjectUtil.isNotNull(response.getData())
                    && response.getData().toString().startsWith(CommonConstants.FLOW_PERFIX)) {
                // F_CH1 --> 具体的操作
                JSONArray jsonArray = WebUtils.getDict(KEY);
                Optional<String> first = jsonArray.stream()
                        .filter(e -> response.getData().toString().equals(((JSONObject) e).get(CommonConstants.DICT_VALUE)))
                        .map(e -> ((JSONObject) e).get(CommonConstants.DICT_LABEL).toString())
                        .findFirst();
                if (first.isPresent()) {
                    dto.setOperation(first.get());
                }
            }
        }
    }

    *//**
     * 装载key和notes
     *
     * @param point
     * @param operationLog
     * @param dto
     *//*
    private void setKeyAndNotes(ProceedingJoinPoint point, OperationLog operationLog, OperationLogDTO dto) {
        MethodSignature signature = (MethodSignature) point.getSignature();
        // 参数名
        String[] parameterNames = signature.getParameterNames();
        // 参数值
        Object[] args = point.getArgs();

        for (int i = 0; i < parameterNames.length; i++) {
            if (ObjectUtil.isNull(args[i]) || ObjectUtil.isNull(parameterNames[i])) {
                return;
            }
            // 获取参数列表（基本类型或者为String）属性名为key、notes的值
            if (ClassUtil.isBasicType(args[i].getClass()) || CharSequence.class.isAssignableFrom(args[i].getClass())) {
                if (parameterNames[i].equals(operationLog.keyName())) {
                    dto.setTargetKey(objToString(args[i]));
                    continue;
                }
                if (parameterNames[i].equals(operationLog.notesName())) {
                    dto.setNotes(objToString(args[i]));
                }
            } else {
                // 获取参数列表的实体类中属性名为key、notes的值
                Field[] fields = ReflectUtil.getFields(args[i].getClass());
                if (ArrayUtil.isNotEmpty(fields)) {
                    for (Field field : fields) {
                        if (field.getName().equals(operationLog.keyName())) {
                            dto.setTargetKey(objToString(ReflectUtil.getFieldValue(args[i], operationLog.keyName())));
                            continue;
                        }
                        if (field.getName().equals(operationLog.notesName())) {
                            dto.setNotes(objToString(ReflectUtil.getFieldValue(args[i], operationLog.notesName())));
                        }
                    }
                }
            }
        }
    }

    private String objToString(Object obj) {
        return ObjectUtil.isNull(obj) ? null : obj.toString();
    }*/

}
